//+------------------------------------------------------------------+
//|                                                      BollingEx.mq5 |
//|                                                                     |
//|                                                                     |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property link      ""
#property version   "1.00"

// 外部参数
input int      BB_Period = 20;                // 布林带周期
input double   BB_Deviation = 2.0;            // 布林带标准差倍数
input ENUM_APPLIED_PRICE BB_PriceType = PRICE_CLOSE; // 布林带价格类型
input double   InitialLot = 0.1;              // 初始手数
input int      Magic = 123456;                // EA魔术号
input int      ATRPeriod = 14;                // ATR周期
input double   ATRMultiplier = 3.0;           // ATR倍数
input int      ADXPeriod = 14;                // ADX周期
input int      ADXThreshold = 25;             // ADX阈值
input int      RSIPeriod = 14;                // RSI周期
input int      MACDFastEMA = 12;              // MACD快线
input int      MACDSlowEMA = 26;              // MACD慢线
input int      MACDSignalPeriod = 9;          // MACD信号线
input double   TrendBandWidthThreshold = 0.15; // 趋势带宽阈值
input double   SidewaySlopeThreshold = 0.087;  // 震荡斜率阈值(5度)
input double   TiltSlopeThreshold = 0.175;     // 倾斜斜率阈值(10度)
input double   BufferZoneATR = 0.5;           // 缓冲带ATR倍数
input int      MinCandleBodyPercent = 60;     // 最小K线实体占比
input double   MaxShadowRatio = 0.5;          // 最大影线比例
input double   MinVolatilityATR = 0.0035;     // 最小波动率

// 全局变量
int g_bbHandle;                       // 布林带指标句柄
int g_atrHandle;                      // ATR指标句柄
int g_adxHandle;                      // ADX指标句柄
int g_rsiHandle;                      // RSI指标句柄
int g_macdHandle;                     // MACD指标句柄
double g_bbUpperBuffer[];             // 布林带上轨
double g_bbMiddleBuffer[];            // 布林带中轨
double g_bbLowerBuffer[];             // 布林带下轨
double g_atrBuffer[];                 // ATR缓冲区
double g_adxBuffer[];                 // ADX缓冲区
double g_rsiBuffer[];                 // RSI缓冲区
double g_macdMainBuffer[];            // MACD主缓冲区
double g_macdSignalBuffer[];          // MACD信号缓冲区
datetime g_lastBarTime = 0;           // 上次K线时间

// 市场状态枚举
enum MarketState {
    MARKET_SIDEWAYS,    // 震荡行情
    MARKET_TREND,       // 趋势行情
    MARKET_TILT         // 倾斜行情
};

//+------------------------------------------------------------------+
//| 计算布林带带宽                                                    |
//+------------------------------------------------------------------+
double CalculateBandWidth(int shift)
{
    double upper = g_bbUpperBuffer[shift];
    double lower = g_bbLowerBuffer[shift];
    double middle = g_bbMiddleBuffer[shift];
    
    if(middle == 0) return 0;
    return (upper - lower) / middle;
}

//+------------------------------------------------------------------+
//| 计算带宽移动平均                                                  |
//+------------------------------------------------------------------+
double CalculateBandWidthMA(int period)
{
    if(period <= 0) return 0;
    
    double sum = 0;
    int count = 0;
    
    for(int i = 0; i < period; i++)
    {
        if(i >= ArraySize(g_bbUpperBuffer) || 
           i >= ArraySize(g_bbLowerBuffer) || 
           i >= ArraySize(g_bbMiddleBuffer))
            break;
            
        double upper = g_bbUpperBuffer[i];
        double lower = g_bbLowerBuffer[i];
        double middle = g_bbMiddleBuffer[i];
        
        if(middle != 0)
        {
            sum += (upper - lower) / middle;
            count++;
        }
    }
    
    return (count > 0) ? sum / count : 0;
}

//+------------------------------------------------------------------+
//| 计算带宽斜率                                                      |
//+------------------------------------------------------------------+
double CalculateBandWidthSlope(int period)
{
    if(period <= 0) return 0;
    
    // 检查数组大小
    if(ArraySize(g_bbUpperBuffer) <= period + 1) return 0;
    
    double currentMA = CalculateBandWidthMA(period);
    double prevMA = CalculateBandWidthMA(period + 1);
    
    if(currentMA == 0 || prevMA == 0) return 0;
    
    return MathArctan(currentMA - prevMA);
}

//+------------------------------------------------------------------+
//| 判断市场状态                                                      |
//+------------------------------------------------------------------+
MarketState DetermineMarketState()
{
    // 获取指标数据
    double adx = g_adxBuffer[0];
    double bandWidthSlope = CalculateBandWidthSlope(10);
    double macdMain = g_macdMainBuffer[0];
    double macdSignal = g_macdSignalBuffer[0];
    double prevMacdMain = (ArraySize(g_macdMainBuffer) > 1) ? g_macdMainBuffer[1] : 0;
    double prevMacdSignal = (ArraySize(g_macdSignalBuffer) > 1) ? g_macdSignalBuffer[1] : 0;
    
    // 判断趋势行情
    Print("趋势判断 - ADX:", adx, " 阈值:", ADXThreshold, " 贴轨:", IsPriceFollowingBand());
    if(adx > ADXThreshold && IsPriceFollowingBand())
    {
        return MARKET_TREND;
    }
    
    // 判断震荡行情
    Print("震荡判断 - 斜率:", bandWidthSlope, " 阈值:", SidewaySlopeThreshold);
    if(MathAbs(bandWidthSlope) < SidewaySlopeThreshold)
    {
        return MARKET_SIDEWAYS;
    }
    
    // 判断倾斜行情
    double currentMacdDiff = MathAbs(macdMain - macdSignal);
    double prevMacdDiff = MathAbs(prevMacdMain - prevMacdSignal);
    Print("倾斜判断 - 斜率:", bandWidthSlope, " 阈值:", TiltSlopeThreshold, 
          " MACD差值:", currentMacdDiff, 
          " 前值:", prevMacdDiff);
    if(MathAbs(bandWidthSlope) > TiltSlopeThreshold && 
       currentMacdDiff < prevMacdDiff)
    {
        return MARKET_TILT;
    }
    
    return MARKET_SIDEWAYS; // 默认返回震荡状态
}

//+------------------------------------------------------------------+
//| 检查价格是否贴轨运行                                              |
//+------------------------------------------------------------------+
bool IsPriceFollowingBand()
{
    MqlRates rates[];
    ArraySetAsSeries(rates, true);
    if(CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, rates) < 5) return false;
    
    int upperCount = 0;
    int lowerCount = 0;
    
    // 检查当前价格
    double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    
    if(currentBid > g_bbUpperBuffer[0] || currentAsk > g_bbUpperBuffer[0])
        upperCount++;
    if(currentBid < g_bbLowerBuffer[0] || currentAsk < g_bbLowerBuffer[0])
        lowerCount++;
    
    // 检查历史K线
    for(int i = 1; i < 5; i++)
    {
        if(rates[i].close > g_bbUpperBuffer[i] || rates[i].high > g_bbUpperBuffer[i])
            upperCount++;
        if(rates[i].close < g_bbLowerBuffer[i] || rates[i].low < g_bbLowerBuffer[i])
            lowerCount++;
    }
    
    return (upperCount >= 3 || lowerCount >= 3);
}

//+------------------------------------------------------------------+
//| 检查K线形态                                                       |
//+------------------------------------------------------------------+
bool IsValidCandlePattern(const MqlRates &rate)
{
    double bodySize = MathAbs(rate.close - rate.open);
    double upperShadow = rate.high - MathMax(rate.open, rate.close);
    double lowerShadow = MathMin(rate.open, rate.close) - rate.low;
    double totalSize = rate.high - rate.low;
    
    if(totalSize == 0) return false;
    
    // 检查实体占比
    double bodyPercent = (bodySize / totalSize) * 100;
    if(bodyPercent < MinCandleBodyPercent) return false;
    
    // 检查影线比例
    if(upperShadow > bodySize * MaxShadowRatio || 
       lowerShadow > bodySize * MaxShadowRatio)
        return false;
    
    return true;
}

//+------------------------------------------------------------------+
//| 检查波动率                                                        |
//+------------------------------------------------------------------+
bool IsValidVolatility()
{
    double atr = g_atrBuffer[0];
    double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    return (atr >= currentPrice * MinVolatilityATR);
}

//+------------------------------------------------------------------+
//| 计算动态止损                                                      |
//+------------------------------------------------------------------+
double CalculateDynamicStopLoss(int type, double entryPrice)
{
    double atr = g_atrBuffer[0];
    MarketState state = DetermineMarketState();
    
    switch(state)
    {
        case MARKET_SIDEWAYS:
            // 震荡行情使用固定止损
            return (type == POSITION_TYPE_BUY) ? 
                   entryPrice - ATRMultiplier * atr : 
                   entryPrice + ATRMultiplier * atr;
            
        case MARKET_TREND:
            // 趋势行情使用吊灯止损
            if(type == POSITION_TYPE_BUY)
            {
                double highestHigh = iHigh(_Symbol, PERIOD_CURRENT, iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, 50, 0));
                return highestHigh - ATRMultiplier * atr;
            }
            else
            {
                double lowestLow = iLow(_Symbol, PERIOD_CURRENT, iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, 50, 0));
                return lowestLow + ATRMultiplier * atr;
            }
            
        case MARKET_TILT:
            // 倾斜行情使用中轨止损
            return g_bbMiddleBuffer[0];
            
        default:
            return 0;
    }
}

//+------------------------------------------------------------------+
//| 计算动态止盈                                                      |
//+------------------------------------------------------------------+
double CalculateDynamicTakeProfit(int type, double entryPrice)
{
    MarketState state = DetermineMarketState();
    
    switch(state)
    {
        case MARKET_SIDEWAYS:
            // 震荡行情使用反向轨道止盈
            return (type == POSITION_TYPE_BUY) ? 
                   g_bbUpperBuffer[0] : 
                   g_bbLowerBuffer[0];
            
        case MARKET_TREND:
            // 趋势行情使用移动止盈
            return 0; // 趋势行情不使用固定止盈，而是使用移动止损
            
        case MARKET_TILT:
            // 倾斜行情使用中轨止盈
            return g_bbMiddleBuffer[0];
            
        default:
            return 0;
    }
}

//+------------------------------------------------------------------+
//| 检查开仓条件                                                      |
//+------------------------------------------------------------------+
bool CheckEntryConditions(int type)
{
    MarketState state = DetermineMarketState();
    double rsi = g_rsiBuffer[0];
    double atr = g_atrBuffer[0];
    
    // 获取当前价格
    double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    
    // 获取历史K线数据
    MqlRates rates[];
    ArraySetAsSeries(rates, true);
    if(CopyRates(_Symbol, PERIOD_CURRENT, 0, 1, rates) < 1) return false;
    
    // 检查K线形态
    if(!IsValidCandlePattern(rates[0])) return false;
    
    // 检查波动率
    if(!IsValidVolatility()) return false;
    
    // 根据不同市场状态检查开仓条件
    switch(state)
    {
        case MARKET_SIDEWAYS:
            if(type == POSITION_TYPE_BUY)
                return (currentAsk > currentBid && // 确保有足够的价差
                       currentBid < g_bbLowerBuffer[0] && // 当前价格在下轨下方
                       currentAsk > g_bbLowerBuffer[0]); // 买入价在下轨上方
            else
                return (currentAsk > currentBid && // 确保有足够的价差
                       currentAsk > g_bbUpperBuffer[0] && // 当前价格在上轨上方
                       currentBid < g_bbUpperBuffer[0]); // 卖出价在上轨下方
            
        case MARKET_TREND:
            // 趋势行情只在中轨附近开仓
            if(type == POSITION_TYPE_BUY)
                return (currentAsk > g_bbMiddleBuffer[0] - BufferZoneATR * atr &&
                       currentAsk < g_bbMiddleBuffer[0] + BufferZoneATR * atr &&
                       rsi > 40);
            else
                return (currentBid < g_bbMiddleBuffer[0] + BufferZoneATR * atr &&
                       currentBid > g_bbMiddleBuffer[0] - BufferZoneATR * atr &&
                       rsi < 60);
            
        case MARKET_TILT:
            // 倾斜行情需要方向一致
            if(type == POSITION_TYPE_BUY)
                return (g_bbMiddleBuffer[0] > g_bbMiddleBuffer[1] && // 中轨向上倾斜
                       g_atrBuffer[0] > g_atrBuffer[1]); // 波动率扩张
            else
                return (g_bbMiddleBuffer[0] < g_bbMiddleBuffer[1] && // 中轨向下倾斜
                       g_atrBuffer[0] > g_atrBuffer[1]); // 波动率扩张
            
        default:
            return false;
    }
}

//+------------------------------------------------------------------+
//| 显示市场状态                                                      |
//+------------------------------------------------------------------+
void DisplayMarketState()
{
    MarketState state = DetermineMarketState();
    string stateText = "";
    
    switch(state)
    {
        case MARKET_SIDEWAYS:
            stateText = "市场状态: 震荡行情";
            break;
        case MARKET_TREND:
            stateText = "市场状态: 趋势行情";
            break;
        case MARKET_TILT:
            stateText = "市场状态: 倾斜行情";
            break;
    }
    
    Comment(stateText);
}

//+------------------------------------------------------------------+
//| Expert initialization function                                     |
//+------------------------------------------------------------------+
int OnInit()
{
    // 初始化指标句柄
    g_bbHandle = iBands(_Symbol, PERIOD_CURRENT, BB_Period, 0, BB_Deviation, BB_PriceType);
    g_atrHandle = iATR(_Symbol, PERIOD_CURRENT, ATRPeriod);
    g_adxHandle = iADX(_Symbol, PERIOD_CURRENT, ADXPeriod);
    g_rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE);
    g_macdHandle = iMACD(_Symbol, PERIOD_CURRENT, MACDFastEMA, MACDSlowEMA, MACDSignalPeriod, PRICE_CLOSE);
    
    if(g_bbHandle == INVALID_HANDLE || g_atrHandle == INVALID_HANDLE || 
       g_adxHandle == INVALID_HANDLE || g_rsiHandle == INVALID_HANDLE || 
       g_macdHandle == INVALID_HANDLE)
    {
        Print("指标初始化失败!");
        return INIT_FAILED;
    }
    
    // 分配数组内存
    ArraySetAsSeries(g_bbUpperBuffer, true);
    ArraySetAsSeries(g_bbMiddleBuffer, true);
    ArraySetAsSeries(g_bbLowerBuffer, true);
    ArraySetAsSeries(g_atrBuffer, true);
    ArraySetAsSeries(g_adxBuffer, true);
    ArraySetAsSeries(g_rsiBuffer, true);
    ArraySetAsSeries(g_macdMainBuffer, true);
    ArraySetAsSeries(g_macdSignalBuffer, true);
    
    // 初始化数组大小
    ArrayResize(g_bbUpperBuffer, 100);
    ArrayResize(g_bbMiddleBuffer, 100);
    ArrayResize(g_bbLowerBuffer, 100);
    ArrayResize(g_atrBuffer, 100);
    ArrayResize(g_adxBuffer, 100);
    ArrayResize(g_rsiBuffer, 100);
    ArrayResize(g_macdMainBuffer, 100);
    ArrayResize(g_macdSignalBuffer, 100);
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // 释放指标句柄
    if(g_bbHandle != INVALID_HANDLE) IndicatorRelease(g_bbHandle);
    if(g_atrHandle != INVALID_HANDLE) IndicatorRelease(g_atrHandle);
    if(g_adxHandle != INVALID_HANDLE) IndicatorRelease(g_adxHandle);
    if(g_rsiHandle != INVALID_HANDLE) IndicatorRelease(g_rsiHandle);
    if(g_macdHandle != INVALID_HANDLE) IndicatorRelease(g_macdHandle);
}

//+------------------------------------------------------------------+
//| Expert tick function                                              |
//+------------------------------------------------------------------+
void OnTick()
{
    // 检查新K线
    datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
    if(currentBarTime == g_lastBarTime) return;
    g_lastBarTime = currentBarTime;
    
    // 更新指标数据
    if(CopyBuffer(g_bbHandle, 1, 0, 100, g_bbUpperBuffer) <= 0) return;
    if(CopyBuffer(g_bbHandle, 0, 0, 100, g_bbMiddleBuffer) <= 0) return;
    if(CopyBuffer(g_bbHandle, 2, 0, 100, g_bbLowerBuffer) <= 0) return;
    if(CopyBuffer(g_atrHandle, 0, 0, 100, g_atrBuffer) <= 0) return;
    if(CopyBuffer(g_adxHandle, 0, 0, 100, g_adxBuffer) <= 0) return;
    if(CopyBuffer(g_rsiHandle, 0, 0, 100, g_rsiBuffer) <= 0) return;
    if(CopyBuffer(g_macdHandle, 0, 0, 100, g_macdMainBuffer) <= 0) return;
    if(CopyBuffer(g_macdHandle, 1, 0, 100, g_macdSignalBuffer) <= 0) return;
    
    // 显示市场状态
    DisplayMarketState();
    
    // 检查是否有持仓
    bool hasPosition = false;
    for(int i = 0; i < PositionsTotal(); i++)
    {
        if(PositionSelectByTicket(PositionGetTicket(i)))
        {
            if(PositionGetString(POSITION_SYMBOL) == _Symbol && 
               PositionGetInteger(POSITION_MAGIC) == Magic)
            {
                hasPosition = true;
                break;
            }
        }
    }
    
    // 如果没有持仓，检查开仓条件
    if(!hasPosition)
    {
        // 检查买入条件
        if(CheckEntryConditions(POSITION_TYPE_BUY))
        {
            double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            double stopLoss = CalculateDynamicStopLoss(POSITION_TYPE_BUY, entryPrice);
            double takeProfit = CalculateDynamicTakeProfit(POSITION_TYPE_BUY, entryPrice);
            
            MqlTradeRequest request = {};
            MqlTradeResult result = {};
            
            request.action = TRADE_ACTION_DEAL;
            request.symbol = _Symbol;
            request.volume = InitialLot;
            request.type = ORDER_TYPE_BUY;
            request.price = entryPrice;
            request.sl = stopLoss;
            request.tp = takeProfit;
            request.deviation = 10;
            request.magic = Magic;
            
            OrderSend(request, result);
        }
        
        // 检查卖出条件
        if(CheckEntryConditions(POSITION_TYPE_SELL))
        {
            double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            double stopLoss = CalculateDynamicStopLoss(POSITION_TYPE_SELL, entryPrice);
            double takeProfit = CalculateDynamicTakeProfit(POSITION_TYPE_SELL, entryPrice);
            
            MqlTradeRequest request = {};
            MqlTradeResult result = {};
            
            request.action = TRADE_ACTION_DEAL;
            request.symbol = _Symbol;
            request.volume = InitialLot;
            request.type = ORDER_TYPE_SELL;
            request.price = entryPrice;
            request.sl = stopLoss;
            request.tp = takeProfit;
            request.deviation = 10;
            request.magic = Magic;
            
            OrderSend(request, result);
        }
    }
    else
    {
        // 更新移动止损
        for(int i = 0; i < PositionsTotal(); i++)
        {
            if(PositionSelectByTicket(PositionGetTicket(i)))
            {
                if(PositionGetString(POSITION_SYMBOL) == _Symbol && 
                   PositionGetInteger(POSITION_MAGIC) == Magic)
                {
                    int type = PositionGetInteger(POSITION_TYPE);
                    double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN);
                    double currentSL = PositionGetDouble(POSITION_SL);
                    double newSL = CalculateDynamicStopLoss(type, entryPrice);
                    
                    // 如果是趋势行情，使用移动止损
                    if(DetermineMarketState() == MARKET_TREND)
                    {
                        if((type == POSITION_TYPE_BUY && newSL > currentSL) ||
                           (type == POSITION_TYPE_SELL && (newSL < currentSL || currentSL == 0)))
                        {
                            MqlTradeRequest request = {};
                            MqlTradeResult result = {};
                            
                            request.action = TRADE_ACTION_SLTP;
                            request.position = PositionGetTicket(i);
                            request.symbol = _Symbol;
                            request.sl = newSL;
                            request.tp = PositionGetDouble(POSITION_TP);
                            
                            OrderSend(request, result);
                        }
                    }
                }
            }
        }
    }
} 